import { PagePath } from "@/constants/pageMap"
import Taro from "@tarojs/taro"
import { serialize } from "query-parse-serialize"
import { isSetValue } from "@/utils/helper"

interface NavigateBackOptionMap {
  "navigateBack": Taro.navigateBack.Option
}

interface NavigateOptionMap {
  "navigateTo": Omit<Taro.navigateTo.Option, "url">
  "reLaunch": Omit<Taro.reLaunch.Option, "url">
  "switchTab": Omit<Taro.switchTab.Option, "url">
  "redirectTo": Omit<Taro.redirectTo.Option, "url">
}

interface NavigateMap extends NavigateBackOptionMap, NavigateOptionMap {}

export function navigate<T extends keyof NavigateBackOptionMap = "navigateBack">(
  backOptions?: NavigateBackOptionMap[T]
): Promise<TaroGeneral.CallbackResult>
export function navigate<T extends keyof NavigateOptionMap = "navigateTo">(
  pathOrPluginPageName: PagePath,
  query?: Recordable | null,
  openType?: T,
  option?: NavigateOptionMap[T],
  pluginName?: string
): Promise<TaroGeneral.CallbackResult>
export function navigate<T extends keyof NavigateMap = "navigateTo">(
  backOptionsOrPathOrPluginPageName: PagePath | NavigateBackOptionMap["navigateBack"],
  query?: Recordable | null,
  openType?: T,
  option?: NavigateMap[T],
  pluginName?: string
) {
  if (!isSetValue(backOptionsOrPathOrPluginPageName)
    || typeof backOptionsOrPathOrPluginPageName === "object"
  ) {
    return Taro["navigateBack"](backOptionsOrPathOrPluginPageName)
  }
  const url = makePagePath(backOptionsOrPathOrPluginPageName, query, pluginName)
  return Taro[openType ?? "navigateTo"]({
    url,
    ...option
  })
}

export const makePagePath = function (
  pathOrPluginPageName: PagePath,
  query?: Recordable | null,
  pluginName?: string
) {
  const search = query ? serialize(query, { withPrefix: true }) : ""
  const prefix = pluginName ? `plugin://${pluginName}/` : "/"
  return [prefix, pathOrPluginPageName, search].join("")
}
